package google.RateLimiter;


import static com.google.common.collect.Range.lessThan;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;

import com.google.common.util.concurrent.RateLimiter;
import java.time.ZonedDateTime;
import java.util.concurrent.TimeUnit;
import java.util.stream.IntStream;
import org.junit.Test;

public class RateLimiterTest {


  @Test
  public void givenLimitedResource_whenRequestOnce_thenShouldPermitWithoutBlocking() {
    // given
    RateLimiter rateLimiter = RateLimiter.create(100);

    // when
    long startTime = ZonedDateTime.now().getSecond();
    rateLimiter.acquire(100);
    doSomeLimitedOperation();
    long elapsedTimeSeconds = ZonedDateTime.now().getSecond() - startTime;

    // then
    assertTrue(elapsedTimeSeconds < 1);
  }

  private void doSomeLimitedOperation() {
    System.out.println(Thread.currentThread().getName() + "-->working.");
  }

  @Test
  public void givenLimitedResource_whenUseRateLimiter_thenShouldLimitPermits() {
    // given
    RateLimiter rateLimiter = RateLimiter.create(100);

    // when
    long startTime = ZonedDateTime.now().getSecond();
    IntStream.range(0, 1000).forEach(i -> {
      //rateLimiter.acquire();
      doSomeLimitedOperation();
      System.out.print(i);
    });
    long elapsedTimeSeconds = ZonedDateTime.now().getSecond() - startTime;

    // then
    //assertTrue(elapsedTimeSeconds >= 10);
    System.out.println("elapsedTimeSeconds===>" + elapsedTimeSeconds);
  }

  @Test
  public void givenLimitedResource_whenTryAcquire_shouldNotBlockIndefinitely() {
    // given
    RateLimiter rateLimiter = RateLimiter.create(1);

    // when
    rateLimiter.acquire();
    boolean result = rateLimiter.tryAcquire(2, 1000, TimeUnit.MILLISECONDS);

    // then
    assertFalse(result);
  }


}
